﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using OpenTK;
using OpenTK.Graphics.OpenGL4;
using SDL3;
using Silk.NET.SDL;
using static SDL3.SDL;

namespace 飞机大战
{
    internal partial class Game
    {
        public static partial Game GetInstance()
        {
             if (instance == null)
             {
                 instance = new Game();
             }
             return instance;
        }

        public class DesktopGLContext : IBindingsContext
        {
            public IntPtr GetProcAddress(string procName)
            {
                // 使用 OpenTK 提供的默认绑定上下文获取函数指针
                FunctionPointer functionPointer = SDL.GLGetProcAddress(procName);
               
                return functionPointer == null ? IntPtr.Zero : Marshal.GetFunctionPointerForDelegate(functionPointer);
            }
        }

        public partial void Init(string title, int width, int height)
        {
            // 获取宽度高度
            this.width_ = width;
            this.height_ = height;
            // SDL3初始化 SDL.Init(SDL.InitFlags.Video)
            // 初始化视频和事件系统
            if (!SDL.Init(SDL.InitFlags.Video | SDL.InitFlags.Events | SDL.InitFlags.Audio))
            {
                throw new Exception($"SDL初始化失败: {_sdl.GetErrorS()}");
            }
            // SDL3_Mixer 初始化
            if (Mixer.Init(Mixer.InitFlags.MP3 | Mixer.InitFlags.OGG) != (Mixer.InitFlags.MP3 | Mixer.InitFlags.OGG))
            { 
                SDL.LogError(SDL.LogCategory.Application, $"SDL_Mixer初始化失败: {SDL.GetError()} \n");
            }
            if (!Mixer.OpenAudio(0, 0))
            {
                SDL.LogError(SDL.LogCategory.Application, $"SDL音频初始化失败: {SDL.GetError()} \n");
            }
            Mixer.AllocateChannels(16); // 分配16个音频通道
            Mixer.VolumeMusic(Mixer.MaxVolume / 4);
            Mixer.Volume(-1, Mixer.MaxVolume / 4);

            // SDL3_TTF初始化
            if (!TTF.Init())
            {
                SDL.LogError(SDL.LogCategory.Application, $"SDL_TTF初始化失败: {SDL.GetError()} \n");
            }
            // 渲染器和窗口初始化
            //if (!SDL.CreateWindowAndRenderer(title, width, height, 0, out var window, out var renderer))
            //{
            //    SDL.LogError(SDL.LogCategory.Application, $"Error creating window and rendering: {SDL.GetError()}");
            //    return;
            //}
            //else
            //{
            //    this.window_ = window;
            //    this.render_ = renderer;
            //}
            SDL.GLSetAttribute(SDL.GLAttr.ContextMajorVersion, 4);
            SDL.GLSetAttribute(SDL.GLAttr.ContextMinorVersion, 3);
            SDL.GLSetAttribute(SDL.GLAttr.ContextProfileMask, (int)SDL.GLProfile.Core);

            IntPtr window = SDL.CreateWindow(title, width, height, SDL.WindowFlags.OpenGL);
            this.window_ = window;
            IntPtr glContext = SDL.GLCreateContext(window);
            SDL.GLMakeCurrent(this.window_, glContext);
            GL.LoadBindings(new DesktopGLContext());

            // 计算帧延迟
            frame_delay_ = (ulong)(1000000000 / FPS_);

            // 创建场景
            current_scene_ = new scene.SceneMain();
            current_scene_.Init();
        }

        public partial void HandleEvents()
        {
            while (SDL.PollEvent(out var e))
            { 
                switch (e.Type)
                {
                case ((uint)SDL.EventType.Quit):
                    this.is_running_ = false;
                    break;
                default:
                    this.current_scene_.HandleEvents(e);
                    break;
                }
            }
        }

        public partial void Update(float dt)
        {
            current_scene_.Update(dt);
        }

        public partial void Render()
        {
            GL.Clear(ClearBufferMask.ColorBufferBit);
            current_scene_.Render();
            SDL.GLSwapWindow(window_);
        }

        public partial void Clean()
        {
            current_scene_.Clean();

            // 清理资源
            SDL.GLDestroyContext(SDL.GLGetCurrentContext());

            if (window_ != -1)
            {
                SDL.DestroyWindow(window_);
            }

            Mixer.CloseAudio();

            Mixer.Quit();

            TTF.Quit();

            SDL.Quit();
        }

        public partial void Run()
        {
            while (is_running_)
            {
                var start = SDL.GetTicksNS();
                HandleEvents();
                Update(dt_);
                Render();
                var elapsed = SDL.GetTicksNS() - start;
                if (elapsed < frame_delay_)
                {
                    SDL.DelayNS((frame_delay_ - elapsed));
                    dt_ = frame_delay_;
                }
                else
                {
                    dt_ = elapsed;
                }
                SDL.Log("FPS:" + (float)(1000000000 / dt_));
            }
        }
    }
}
